package com.jilefojing.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.jilefojing.beans.data.enums.ResponseEnum;
import com.jilefojing.beans.enums.ItemTypeEnumForSource;
import com.jilefojing.beans.exception.UserContextException;
import com.jilefojing.beans.pojos.DCategory;
import com.jilefojing.beans.pojos.RCategorySource;
import com.jilefojing.beans.pojos.enhanced.EnhancedDCategory;
import com.jilefojing.beans.pojos.enhanced.EnhancedUser;
import com.jilefojing.beans.query.DCategoryQuery;
import com.jilefojing.beans.vo.Order;
import com.jilefojing.beans.vo.Pagination;
import com.jilefojing.context.beans.vo.UserContext;
import com.jilefojing.dao.IDCategoryDao;
import com.jilefojing.dao.IRCategorySourceDao;
import com.jilefojing.service.IDCategoryService;
import com.jilefojing.service.IUserService;
import com.jilefojing.service.base.impl.BaseService;
import com.jilefojing.util.Detect;

/**
 * 
 * @author 作者 jgshun
 * @date 创建时间 2016年07月26日 16时31分05秒
 */
@Service
public class DCategoryService extends BaseService<DCategory> implements IDCategoryService {
	@Autowired
	private IDCategoryDao dCategoryDao;
	@Autowired
	private IUserService userService;
	@Autowired
	private IRCategorySourceDao rCategorySourceDao;

	@Override
	public Pagination<EnhancedDCategory> getPagination(DCategoryQuery dCategoryQuery, Pagination<EnhancedDCategory> pagination, UserContext userContext) {
		@SuppressWarnings("unchecked")
		Pagination<DCategory> rCategorySourcePagination = dCategoryDao.getPagination(dCategoryQuery, pagination.copy());
		pagination.setCount(rCategorySourcePagination.getCount());
		if (!Detect.notEmpty(rCategorySourcePagination.getItems())) {
			return pagination;
		}
		pagination.setItems(this.conventDCategorys2EnhancedDCategories(rCategorySourcePagination.getItems()));
		this.appendEnhancedCommons(pagination.getItems());
		return pagination;
	}

	private void appendEnhancedCommons(List<EnhancedDCategory> enhancedChildDCategories) {
		this.appendEnhancedUser2EnhancedDCategories(enhancedChildDCategories);

	}

	private void appendEnhancedUser2EnhancedDCategories(List<EnhancedDCategory> enhancedChildDCategories) {
		List<Long> userIds = new ArrayList<Long>();
		for (EnhancedDCategory _EnhancedDCategory : enhancedChildDCategories) {
			if (_EnhancedDCategory.getEnhancedCreateUser() != null) {
				userIds.add(_EnhancedDCategory.getEnhancedCreateUser().getId());
			}
		}

		if (!Detect.notEmpty(userIds)) {
			return;
		}
		List<EnhancedUser> enhancedUsers = userService.getEnhancedUsers(userIds);
		if (!Detect.notEmpty(enhancedUsers)) {
			return;
		}

		for (EnhancedDCategory _EnhancedDCategory : enhancedChildDCategories) {
			if (_EnhancedDCategory.getEnhancedCreateUser() != null) {
				for (EnhancedUser _EnhancedUser : enhancedUsers) {
					if (_EnhancedDCategory.getEnhancedCreateUser().getId() == _EnhancedUser.getId()) {
						_EnhancedDCategory.setEnhancedCreateUser(_EnhancedUser);
						break;
					}
				}

			}
		}
	}

	@Override
	public List<EnhancedDCategory> conventDCategorys2EnhancedDCategories(List<DCategory> dCategories) {
		List<EnhancedDCategory> enhancedDCategories = new ArrayList<EnhancedDCategory>();
		for (DCategory _DCategory : dCategories) {
			enhancedDCategories.add(new EnhancedDCategory(_DCategory));
		}
		return enhancedDCategories;
	}

	@Override
	public List<EnhancedDCategory> getEnhancedTopDCategoriesByItemTypes(List<ItemTypeEnumForSource> itemTypes, UserContext userContext) {
		Pagination<EnhancedDCategory> pagination = new Pagination<EnhancedDCategory>(1, Integer.MAX_VALUE, false);
		pagination.addOrder(new Order(DCategory.COLUMN_SORT, Order.ORDER_DESC));

		DCategoryQuery dCategoryQuery = new DCategoryQuery();
		dCategoryQuery.setItemTypes(itemTypes);
		dCategoryQuery.setEntity(false);

		pagination = this.getPagination(dCategoryQuery, pagination, userContext);

		return pagination.getItems();
	}

	@Override
	public List<EnhancedDCategory> getEnhancedTopDCategoriesByItemType(ItemTypeEnumForSource itemType, UserContext userContext) {
		return this.getEnhancedTopDCategoriesByItemTypes(Arrays.asList(new ItemTypeEnumForSource[] { itemType }), userContext);
	}

	@Override
	public List<EnhancedDCategory> getEnhancedChildDCategoriesByParentIds(List<Long> parentIds, UserContext userContext) {
		Pagination<EnhancedDCategory> pagination = new Pagination<EnhancedDCategory>(1, Integer.MAX_VALUE, false);
		pagination.addOrder(new Order(DCategory.COLUMN_SORT, Order.ORDER_DESC));

		DCategoryQuery dCategoryQuery = new DCategoryQuery();
		dCategoryQuery.setParentIds(parentIds);
		dCategoryQuery.setEntity(true);

		pagination = this.getPagination(dCategoryQuery, pagination, userContext);

		return pagination.getItems();
	}

	@Override
	public EnhancedDCategory appendEnhancedChildDCategories2EnhancedDCategory(EnhancedDCategory enhancedDCategory, UserContext userContext) {
		this.appendEnhancedChildDCategories2EnhancedDCategories(Arrays.asList(new EnhancedDCategory[] { enhancedDCategory }), userContext);
		return enhancedDCategory;
	}

	@Override
	public List<EnhancedDCategory> appendEnhancedChildDCategories2EnhancedDCategories(List<EnhancedDCategory> enhancedDCategories, UserContext userContext) {
		List<Long> parentIds = new ArrayList<Long>();
		for (EnhancedDCategory _EnhancedDCategory : enhancedDCategories) {
			if (!_EnhancedDCategory.isEntity()) {
				parentIds.add(_EnhancedDCategory.getId());
			}
		}
		if (!Detect.notEmpty(parentIds)) {
			return enhancedDCategories;
		}

		List<EnhancedDCategory> enhancedChildDCategories = this.getEnhancedChildDCategoriesByParentIds(parentIds, userContext);
		if (!Detect.notEmpty(enhancedChildDCategories)) {
			return enhancedChildDCategories;
		}

		for (EnhancedDCategory _EnhancedDCategory : enhancedDCategories) {
			if (!_EnhancedDCategory.isEntity()) {
				_EnhancedDCategory.setEnhancedChildDCategories(this.getEnhancedChildDCategories(_EnhancedDCategory, enhancedChildDCategories, userContext));
			}
		}

		return enhancedChildDCategories;
	}

	private List<EnhancedDCategory> getEnhancedChildDCategories(EnhancedDCategory enhancedDCategory, List<EnhancedDCategory> enhancedChildDCategories, UserContext userContext) {
		List<EnhancedDCategory> chileEnhancedDCategories = new ArrayList<EnhancedDCategory>();
		for (EnhancedDCategory _childEnhancedDCategory : enhancedChildDCategories) {
			if (enhancedDCategory.getId() == _childEnhancedDCategory.getEnhancedParentDCategory().getId()) {
				chileEnhancedDCategories.add(_childEnhancedDCategory);
			}
		}
		return chileEnhancedDCategories;
	}

	@Override
	public EnhancedDCategory getEnhancedDCategory(long id, UserContext userContext) {
		List<EnhancedDCategory> enhancedDCategories = this.getEnhancedDCategories(Arrays.asList(new Long[] { id }), userContext);
		if (!Detect.notEmpty(enhancedDCategories)) {
			return null;
		}
		return enhancedDCategories.get(0);
	}

	@Override
	public List<EnhancedDCategory> getEnhancedDCategories(List<Long> ids, UserContext userContext) {
		List<DCategory> dCategories = dCategoryDao.getListByIds(ids);
		if (!Detect.notEmpty(dCategories)) {
			return null;
		}
		return this.conventDCategorys2EnhancedDCategories(dCategories);
	}

	@Override
	public EnhancedDCategory appendEnhancedParentDCategory2EnhancedDCategory(EnhancedDCategory enhancedDCategory, UserContext userContext) {
		this.appendEnhancedParentDCategory2EnhancedDCategories(Arrays.asList(new EnhancedDCategory[] { enhancedDCategory }), userContext);
		return enhancedDCategory;
	}

	@Override
	public List<EnhancedDCategory> appendEnhancedParentDCategory2EnhancedDCategories(List<EnhancedDCategory> enhancedDCategories, UserContext userContext) {
		List<Long> parentIds = new ArrayList<Long>();
		for (EnhancedDCategory _EnhancedDCategory : enhancedDCategories) {
			if (_EnhancedDCategory.getEnhancedParentDCategory() != null) {
				parentIds.add(_EnhancedDCategory.getEnhancedParentDCategory().getId());
			}
		}
		if (!Detect.notEmpty(parentIds)) {
			return enhancedDCategories;
		}
		List<EnhancedDCategory> enhancedParentDCategories = this.getEnhancedDCategories(parentIds, userContext);
		if (!Detect.notEmpty(enhancedParentDCategories)) {
			return enhancedDCategories;
		}

		for (EnhancedDCategory _EnhancedDCategory : enhancedDCategories) {
			if (_EnhancedDCategory.getEnhancedParentDCategory() != null) {
				for (EnhancedDCategory _EnhancedParentDCategory : enhancedParentDCategories) {
					if (_EnhancedDCategory.getEnhancedParentDCategory().getId() == _EnhancedParentDCategory.getId()) {
						_EnhancedDCategory.setEnhancedParentDCategory(_EnhancedParentDCategory);
						break;
					}
				}
			}
		}
		return enhancedDCategories;
	}

	private void deleteByIdsForEntity(List<Long> ids, UserContext userContext) throws UserContextException {
		List<DCategory> dbDCategories = dCategoryDao.getListByIds(ids);
		if (!Detect.notEmpty(dbDCategories)) {
			return;
		}
		this.checkDeleteForEntity(dbDCategories);
		ids = new ArrayList<Long>();
		for (DCategory _dbDCategory : dbDCategories) {
			if (_dbDCategory.getEntity() != 1) {
				throw new UserContextException("[不能操作非实体数据]");
			}
			ids.add(_dbDCategory.getId());
		}
		dCategoryDao.deleteByIds(ids, DCategory.FIELD_ID, DCategory.class);
	}

	private void checkDeleteForEntity(List<DCategory> dbDCategories) throws UserContextException {
		Map<String, List<Long>> categoryMaps = new HashMap<String, List<Long>>();
		for (DCategory _dbDCategory : dbDCategories) {
			if (categoryMaps.get(_dbDCategory.getCkey()) == null) {
				categoryMaps.put(_dbDCategory.getCkey(), new ArrayList<Long>());
			}
			categoryMaps.get(_dbDCategory.getCkey()).add(_dbDCategory.getId());
		}
		Set<Entry<String, List<Long>>> categoryEntrys = categoryMaps.entrySet();
		for (Entry<String, List<Long>> _categoryEntry : categoryEntrys) {
			this.checkDeleteForEntity(_categoryEntry.getKey(), _categoryEntry.getValue());
		}
	}

	private void checkDeleteForEntity(String ckey, List<Long> ids) throws UserContextException {
		int count = rCategorySourceDao.countByCategories(ckey, ids);
		if (count > 0) {
			throw new UserContextException(ResponseEnum.CATEGORY_EXIST_RELATION_SOURCES);
		}
	}

	@Override
	public void deleteByIdsForNotEntity(List<Long> ids, UserContext userContext) throws UserContextException {
		List<DCategory> dbDCategories = dCategoryDao.getListByIds(ids);
		if (!Detect.notEmpty(dbDCategories)) {
			return;
		}
		this.checkDeleteForNotEntity(dbDCategories);
		ids = new ArrayList<Long>();
		for (DCategory _dbDCategory : dbDCategories) {
			ids.add(_dbDCategory.getId());
		}

		dCategoryDao.deleteByIds(ids, DCategory.FIELD_ID, DCategory.class);
	}

	private void checkDeleteForNotEntity(List<DCategory> dbDCategories) throws UserContextException {
		List<Long> ids = new ArrayList<Long>();
		for (DCategory _dbDCategory : dbDCategories) {
			if (_dbDCategory.getEntity() != 0) {
				throw new UserContextException("[不能操作实体数据]");
			}
			ids.add(_dbDCategory.getId());
		}
		int count = dCategoryDao.countByParentIds(ids);
		if (count > 0) {
			throw new UserContextException(ResponseEnum.CATEGORY_EXIST_CHILDREN);
		}

	}

	@Override
	public void deleteByIdsForEntity(List<Long> ids, boolean force, UserContext userContext) throws UserContextException {
		if (!force) {
			this.deleteByIdsForEntity(ids, userContext);
			return;
		}
		List<DCategory> dbDCategories = dCategoryDao.getListByIds(ids);
		if (!Detect.notEmpty(dbDCategories)) {
			return;
		}

		this.updateRemoveSourcesRelationForEntity(dbDCategories);

		dCategoryDao.deleteByIds(ids, DCategory.FIELD_ID, DCategory.class);
	}

	private void updateRemoveSourcesRelationForEntity(List<DCategory> dbDCategories) throws UserContextException {
		Map<String, List<Long>> categoryMaps = new HashMap<String, List<Long>>();
		for (DCategory _dbDCategory : dbDCategories) {
			if (_dbDCategory.getEntity() != 1) {
				throw new UserContextException("[不能操作非实体数据]");
			}

			if (categoryMaps.get(_dbDCategory.getCkey()) == null) {
				categoryMaps.put(_dbDCategory.getCkey(), new ArrayList<Long>());
			}
			categoryMaps.get(_dbDCategory.getCkey()).add(_dbDCategory.getId());
		}
		Set<Entry<String, List<Long>>> categoryEntrys = categoryMaps.entrySet();
		for (Entry<String, List<Long>> _categoryEntry : categoryEntrys) {
			this.updateRemoveSourcesRelation(_categoryEntry.getKey(), _categoryEntry.getValue());
		}

	}

	private void updateRemoveSourcesRelation(String ckey, List<Long> ids) {
		List<RCategorySource> rCategorySources = rCategorySourceDao.getListByCategories(ckey, ids);
		if (Detect.notEmpty(rCategorySources)) {
			ckey = ckey.substring(0, 1).toUpperCase() + ckey.substring(1);
			for (RCategorySource _RCategorySource : rCategorySources) {
				_RCategorySource.set("setCategory" + ckey, 0);
			}
			rCategorySourceDao.updateByIds(rCategorySources);
		}

	}

	@Override
	public void update(DCategory dCategory, UserContext userContext) throws UserContextException {
		DCategory dbDCategory = dCategoryDao.getById(dCategory.getId());
		if (dbDCategory == null) {
			throw new UserContextException("[更新对象不存在]");
		}
		this.checkUpdate(dbDCategory, dCategory.getName());
		dbDCategory.setSort(dCategory.getSort() == null ? 0 : dCategory.getSort());
		dbDCategory.setUpdateTime(new Date());

		dCategoryDao.updateByPrimaryKey(dbDCategory);
	}

	private void checkUpdate(DCategory dbCategory, String newName) throws UserContextException {
		if (newName == null || newName.replaceAll(" ", "").length() < 1) {
			throw new UserContextException("[名称不能为空]");
		}

		newName = newName.replaceAll(" ", "");

		if (dbCategory.getName().equals(newName)) {
			return;
		}
		dbCategory.setName(newName);

		if (dbCategory.getEntity() == 1) {
			int count = rCategorySourceDao.countByCategory(dbCategory.getCkey(), dbCategory.getId());
			if (count > 0) {
				throw new UserContextException(ResponseEnum.CATEGORY_EXIST_RELATION_SOURCES);
			}
		} else {
			int count = dCategoryDao.countByParentId(dbCategory.getId());
			if (count > 0) {
				throw new UserContextException(ResponseEnum.CATEGORY_EXIST_CHILDREN);
			}
		}

	}

	@Override
	public DCategory add(DCategory dCategory, UserContext userContext) throws UserContextException {
		if (!Detect.notEmpty(dCategory.getName()) || dCategory.getName().replaceAll(" ", "").length() < 1) {
			throw new UserContextException("[名称不能为空]");
		}
		if (dCategory.getItemType() == null || ItemTypeEnumForSource.getItemTypeEnumByCode(dCategory.getItemType()) == null) {
			throw new UserContextException("[资源类型不能为空]");
		}

		Date now = new Date();
		dCategory.setId(null);
		dCategory.setCreateTime(now);
		dCategory.setUpdateTime(now);
		dCategory.setCreateUser(userContext.getUserId());
		dCategory.setSort(dCategory.getSort() == null ? 0 : dCategory.getSort());
		dCategory.setName(dCategory.getName().replaceAll(" ", ""));

		if (dCategory.getEntity() == null || dCategory.getEntity() == 1) {
			return this.addEntityDCategory(dCategory, userContext);
		}
		return this.addNotEntityDCategory(dCategory, userContext);
	}

	private DCategory addNotEntityDCategory(DCategory dCategory, UserContext userContext) throws UserContextException {
		if (dCategory.getCkey() == null || dCategory.getCkey().replaceAll(" ", "").length() < 1) {
			throw new UserContextException("[分类集合KEY不能为空]");
		}
		String ckey = dCategory.getCkey().replaceAll(" ", "");
		if (!ckey.matches("^c[1-3]{1}[1-9]{0,1}$")) {
			throw new UserContextException("[分类集合KEY必须是(c1-c33)之间]");
		}
		dCategory.setCkey(ckey);
		dCategory.setEntity((short) 0);

		List<DCategory> dbCategories = dCategoryDao.getListByItemCkey(dCategory.getCkey(), ItemTypeEnumForSource.getItemTypeEnumByCode(dCategory.getItemType()));
		if (Detect.notEmpty(dbCategories)) {
			throw new UserContextException("[已存在此资源的分类集合KEY]");
		}
		dbCategories = dCategoryDao.getListByItemNameForNotEntity(dCategory.getName(), ItemTypeEnumForSource.getItemTypeEnumByCode(dCategory.getItemType()));
		if (Detect.notEmpty(dbCategories)) {
			throw new UserContextException("[已存在此资源的分类集合名称]");
		}

		return dCategoryDao.save(dCategory);
	}

	private DCategory addEntityDCategory(DCategory dCategory, UserContext userContext) throws UserContextException {
		DCategory parentDcCategory = dCategoryDao.getById(dCategory.getParentId());
		if (parentDcCategory == null) {
			throw new UserContextException("[所属分类集合不存在]");
		}
		if (parentDcCategory.getEntity() != 0) {
			throw new UserContextException("[所属的必须是分类集合]");
		}
		dCategory.setCkey(parentDcCategory.getCkey());
		dCategory.setEntity((short) 1);

		List<DCategory> dbCategories = dCategoryDao.getListByItemCategory(dCategory.getCkey(), dCategory.getName(), ItemTypeEnumForSource.getItemTypeEnumByCode(dCategory.getItemType()));
		if (Detect.notEmpty(dbCategories)) {
			throw new UserContextException("[所属分类集合中已存在同名分类]");
		}

		return dCategoryDao.save(dCategory);
	}
}
